/**
 * @license =========================================================
 *          bootstrap-datetimepicker.js
 *          http://www.eyecon.ro/bootstrap-datepicker
 *          ========================================================= Copyright
 *          2012 Stefan Petre
 * 
 * Contributions: - Andrew Rowls - Thiago de Arruda
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License. =========================================================
 */
(function($) {
	var smartPhone = window.orientation != undefined;
	var DateTimePicker = function(element, options) {
		this.id = dpgId++;
		this.init(element, options)
	};
	var dateToDate = function(dt) {
		if (typeof dt === "string") {
			return new Date(dt)
		}
		return dt
	};
	DateTimePicker.prototype = {
		constructor : DateTimePicker,
		init : function(element, options) {
			var icon;
			if (!(options.pickTime || options.pickDate))
				throw new Error("Must choose at least one picker");
			this.options = options;
			this.$element = $(element);
			this.language = options.language in dates ? options.language : "en";
			this.pickDate = options.pickDate;
			this.pickTime = options.pickTime;
			this.isInput = this.$element.is("input");
			this.component = false;
			if (this.$element.find(".input-append")
					|| this.$element.find(".input-prepend"))
				this.component = this.$element.find(".add-on");
			this.format = options.format;
			if (!this.format) {
				if (this.isInput)
					this.format = this.$element.data("format");
				else
					this.format = this.$element.find("input").data("format");
				if (!this.format)
					this.format = "MM/dd/yyyy"
			}
			this._compileFormat();
			if (this.component) {
				icon = this.component.find("i")
			}
			if (this.pickTime) {
				if (icon && icon.length)
					this.timeIcon = icon.data("time-icon");
				if (!this.timeIcon)
					this.timeIcon = "icon-time";
				icon.addClass(this.timeIcon)
			}
			if (this.pickDate) {
				if (icon && icon.length)
					this.dateIcon = icon.data("date-icon");
				if (!this.dateIcon)
					this.dateIcon = "icon-calendar";
				icon.removeClass(this.timeIcon);
				icon.addClass(this.dateIcon)
			}
			this.widget = $(
			getTemplate(options.newId, this.timeIcon, options.pickDate,
					options.pickTime, options.pick12HourFormat,
					options.pickSeconds, options.collapse)).appendTo(
							"#" + options.pickerId);
			this.minViewMode = options.minViewMode
					|| this.$element.data("date-minviewmode") || 0;
			if (typeof this.minViewMode === "string") {
				switch (this.minViewMode) {
				case "months":
					this.minViewMode = 1;
					break;
				case "years":
					this.minViewMode = 2;
					break;
				default:
					this.minViewMode = 0;
					break
				}
			}
			this.viewMode = options.viewMode
					|| this.$element.data("date-viewmode") || 0;
			if (typeof this.viewMode === "string") {
				switch (this.viewMode) {
				case "months":
					this.viewMode = 1;
					break;
				case "years":
					this.viewMode = 2;
					break;
				default:
					this.viewMode = 0;
					break
				}
			}
			this.startViewMode = this.viewMode;
			this.weekStart = options.weekStart
					|| this.$element.data("date-weekstart") || 0;
			this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
			this.setStartDate(options.startDate
					|| this.$element.data("date-startdate"));
			this.setEndDate(options.endDate
					|| this.$element.data("date-enddate"));
			this.fillDow();
			this.fillMonths();
			this.fillHours();
			this.fillMinutes();
			this.fillSeconds();
			this.update();
			this.showMode();
			this._attachDatePickerEvents()
		},
		show : function(e) {
			this.widget.show();
			this.height = this.component ? this.component.outerHeight()
					: this.$element.outerHeight();
			this.place();
			this.$element.trigger({
				type : "show",
				date : this._date
			});
			this._attachDatePickerGlobalEvents();
			if (e) {
				e.stopPropagation();
				e.preventDefault()
			}
		},
		disable : function() {
			this.$element.find("input").prop("disabled", true);
			this._detachDatePickerEvents()
		},
		enable : function() {
			this.$element.find("input").prop("disabled", false);
			this._attachDatePickerEvents()
		},
		hide : function() {
			var collapse = this.widget.find(".collapse");
			for (var i = 0; i < collapse.length; i++) {
				var collapseData = collapse.eq(i).data("collapse");
				if (collapseData && collapseData.transitioning)
					return
			}
			this.widget.hide();
			this.viewMode = this.startViewMode;
			this.showMode();
			//this.set();
			this.$element.trigger({
				type : "hide",
				date : this._date
			});
			this._detachDatePickerGlobalEvents()
		},
		set : function() {
			var formatted = "";
			if (!this._unset)
				formatted = this.formatDate(this._date);
			if (!this.isInput) {
				if (this.component) {
					var input = this.$element.find("input");
					input.val(formatted);
					this._resetMaskPos(input)
				}
				this.$element.data("date", formatted)
			} else {
				this.$element.val(formatted);
				this._resetMaskPos(this.$element)
			}
		},
		setValue : function(newDate) {
			if (!newDate) {
				this._unset = true
			} else {
				this._unset = false
			}
			if (typeof newDate === "string") {
				this._date = this.parseDate(newDate)
			} else if (newDate) {
				this._date = new Date(newDate)
			}
			this.set();
			this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date
					.getUTCMonth(), 1, 0, 0, 0, 0);
			this.fillDate();
			this.fillTime()
		},
		getDate : function() {
			if (this._unset)
				return null;
			return new Date(this._date.valueOf())
		},
		setDate : function(date) {
			if (!date)
				this.setValue(null);
			else
				this.setValue(date.valueOf())
		},
		setStartDate : function(date) {
			if (date != null) {
				this.startDate = date
			} else {
				this.startDate = -Infinity
			}
			
			if (this.viewDate) {
				this.update()
			}
		},
		setEndDate : function(date) {
			if (date != null) {
				this.endDate = date
			} else {
				this.endDate = Infinity
			}
			
			if (this.viewDate) {
				this.update()
			}
		},
		getLocalDate : function() {
			if (this._unset)
				return null;
			var d = this._date;
			return new Date(d.getUTCFullYear(), d.getUTCMonth(),
					d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d
							.getUTCSeconds(), d.getUTCMilliseconds())
		},
		setLocalDate : function(localDate) {
			if (!localDate)
				this.setValue(null);
			else
				this.setValue(Date.UTC(localDate.getFullYear(), localDate
						.getMonth(), localDate.getDate(), localDate.getHours(),
						localDate.getMinutes(), localDate.getSeconds(),
						localDate.getMilliseconds()))
		},
		place : function() {
			var offset = this.component ? this.component.offset()
					: this.$element.offset();
			this.width = this.component ? this.component.outerWidth()
					: this.$element.outerWidth();
			offset.top = offset.top + this.height;
			var $window = $(window);
			if (this.options.width != undefined) {
				this.widget.width(this.options.width)
			}
			if (this.options.orientation == "left") {
				this.widget.addClass("left-oriented");
				offset.left = offset.left - this.widget.width() + 20
			}
			if ($window.width() < offset.left + this.widget.outerWidth()) {
				offset.right = $window.width() - offset.left - this.width;
				offset.left = "auto";
				this.widget.addClass("pull-right")
			} else {
				offset.right = "auto";
				this.widget.removeClass("pull-right")
			}
			var parents = this.$element.parents();
			for (var i = 0; i < parents.length; i++) {
				if ($(parents[i]).css("position") == "relative") {
					var relativeOffset = $(parents[i]).offset();
					offset.left = offset.left - relativeOffset.left;
					offset.top = offset.top - relativeOffset.top + $(parents[i]).scrollTop();
					break
				}
			}
			this.widget.css({
				position : "absolute",
				top : offset.top,
				left : offset.left,
				right : offset.right
			})
		},
		notifyChange : function() {
			this.$element.trigger({
				type : "changeDate",
				date : this.getDate(),
				localDate : this.getLocalDate()
			});
			if (this.externalChange != true) {
				this.ignoreChangeEvent = true; 
				this.$element.find("input").trigger('change');
			}
		},
		update : function(newDate) {
			var dateStr = newDate;
			if (!dateStr) {
				if (this.isInput) {
					dateStr = this.$element.val()
				} else {
					dateStr = this.$element.find("input").val()
				}
				if (dateStr) {
					this._date = this.parseDate(dateStr)
				}
				if (!this._date) {
					var tmp = new Date;
					this._date = UTCDate(tmp.getFullYear(), tmp.getMonth(), tmp
							.getDate(), tmp.getHours(), tmp.getMinutes(), tmp
							.getSeconds(), tmp.getMilliseconds())
				}
			}
			this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date
					.getUTCMonth(), 1, 0, 0, 0, 0);
			this.fillDate();
			this.fillTime()
		},
		fillDow : function() {
			var dowCnt = this.weekStart;
			var html = $("<tr>");
			while (dowCnt < this.weekStart + 7) {
				html.append('<th class="dow">'
						+ dates[this.language].daysMin[dowCnt++ % 7] + "</th>")
			}
			this.widget.find(".datepicker-days thead").append(html)
		},
		fillMonths : function() {
			var html = "";
			var i = 0;
			while (i < 12) {
				html += '<span class="month">'
						+ dates[this.language].monthsShort[i++] + "</span>"
			}
			this.widget.find(".datepicker-months td").append(html)
		},
		fillDate : function() {
			var year = this.viewDate.getUTCFullYear();
			var month = this.viewDate.getUTCMonth();
			var currentDate = UTCDate(this._date.getUTCFullYear(), this._date
					.getUTCMonth(), this._date.getUTCDate(), 0, 0, 0, 0);
			var startYear = typeof this.startDate === "object" ? this.startDate
					.getUTCFullYear() : -Infinity;
			var startMonth = typeof this.startDate === "object" ? this.startDate
					.getUTCMonth()
					: -1;
			var endYear = typeof this.endDate === "object" ? this.endDate
					.getUTCFullYear() : Infinity;
			var endMonth = typeof this.endDate === "object" ? this.endDate
					.getUTCMonth() : 12;
			this.widget.find(".datepicker-days").find(".disabled").removeClass(
					"disabled");
			this.widget.find(".datepicker-months").find(".disabled")
					.removeClass("disabled");
			this.widget.find(".datepicker-years").find(".disabled")
					.removeClass("disabled");
			this.widget.find(".datepicker-days th:eq(1)").text(
					dates[this.language].months[month] + " " + year);
			var prevMonth = UTCDate(year, month - 1, 28, 0, 0, 0, 0);
			var day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(),
					prevMonth.getUTCMonth());
			prevMonth.setUTCDate(day);
			prevMonth.setUTCDate(day
					- (prevMonth.getUTCDay() - this.weekStart + 7) % 7);
			if (year == startYear && month <= startMonth || year < startYear) {
				this.widget.find(".datepicker-days th:eq(0)").addClass(
						"disabled")
			}
			if (year == endYear && month >= endMonth || year > endYear) {
				this.widget.find(".datepicker-days th:eq(2)").addClass(
						"disabled")
			}
			var nextMonth = new Date(prevMonth.valueOf());
			nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
			nextMonth = nextMonth.valueOf();
			var html = [];
			var row;
			var clsName;
			while (prevMonth.valueOf() < nextMonth) {
				if (prevMonth.getUTCDay() === this.weekStart) {
					row = $("<tr>");
					html.push(row)
				}
				clsName = "";
				if (prevMonth.getUTCFullYear() < year
						|| prevMonth.getUTCFullYear() == year
						&& prevMonth.getUTCMonth() < month) {
					clsName += " old"
				} else if (prevMonth.getUTCFullYear() > year
						|| prevMonth.getUTCFullYear() == year
						&& prevMonth.getUTCMonth() > month) {
					clsName += " new"
				}
				if (prevMonth.valueOf() === currentDate.valueOf()) {
					clsName += " active"
				}
				if (prevMonth.valueOf() + 864e5 <= this.startDate) {
					clsName += " disabled"
				}
				if (prevMonth.valueOf() > this.endDate) {
					clsName += " disabled"
				}
				row.append('<td class="day' + clsName + '">'
						+ prevMonth.getUTCDate() + "</td>");
				prevMonth.setUTCDate(prevMonth.getUTCDate() + 1)
			}
			this.widget.find(".datepicker-days tbody").empty().append(html);
			var currentYear = this._date.getUTCFullYear();
			var months = this.widget.find(".datepicker-months")
					.find("th:eq(1)").text(year).end().find("span")
					.removeClass("active");
			if (currentYear === year) {
				months.eq(this._date.getUTCMonth()).addClass("active")
			}
			if (currentYear - 1 < startYear) {
				this.widget.find(".datepicker-months th:eq(0)").addClass(
						"disabled")
			}
			if (currentYear + 1 > endYear) {
				this.widget.find(".datepicker-months th:eq(2)").addClass(
						"disabled")
			}
			for (var i = 0; i < 12; i++) {
				if (year == startYear && startMonth > i || year < startYear) {
					$(months[i]).addClass("disabled")
				} else if (year == endYear && endMonth < i || year > endYear) {
					$(months[i]).addClass("disabled")
				}
			}
			html = "";
			year = parseInt(year / 10, 10) * 10;
			var yearCont = this.widget.find(".datepicker-years").find(
					"th:eq(1)").text(year + "-" + (year + 9)).end().find("td");
			this.widget.find(".datepicker-years").find("th").removeClass(
					"disabled");
			if (startYear > year) {
				this.widget.find(".datepicker-years").find("th:eq(0)")
						.addClass("disabled")
			}
			if (endYear < year + 9) {
				this.widget.find(".datepicker-years").find("th:eq(2)")
						.addClass("disabled")
			}
			year -= 1;
			for (var i = -1; i < 11; i++) {
				html += '<span class="year'
						+ (i === -1 || i === 10 ? " old" : "")
						+ (currentYear === year ? " active" : "")
						+ (year < startYear || year > endYear ? " disabled"
								: "") + '">' + year + "</span>";
				year += 1
			}
			yearCont.html(html)
		},
		fillHours : function() {
			var table = this.widget.find(".timepicker .timepicker-hours table");
			table.parent().hide();
			var html = "";
			if (this.options.pick12HourFormat) {
				var current = 1;
				for (var i = 0; i < 3; i += 1) {
					html += "<tr>";
					for (var j = 0; j < 4; j += 1) {
						var c = current.toString();
						html += '<td class="hour">' + padLeft(c, 2, "0")
								+ "</td>";
						current++
					}
					html += "</tr>"
				}
			} else {
				var current = 0;
				for (var i = 0; i < 6; i += 1) {
					html += "<tr>";
					for (var j = 0; j < 4; j += 1) {
						var c = current.toString();
						html += '<td class="hour">' + padLeft(c, 2, "0")
								+ "</td>";
						current++
					}
					html += "</tr>"
				}
			}
			table.html(html)
		},
		fillMinutes : function() {
			var table = this.widget
					.find(".timepicker .timepicker-minutes table");
			table.parent().hide();
			var html = "";
			var current = 0;
			for (var i = 0; i < 5; i++) {
				html += "<tr>";
				for (var j = 0; j < 4; j += 1) {
					var c = current.toString();
					html += '<td class="minute">' + padLeft(c, 2, "0")
							+ "</td>";
					current += 3
				}
				html += "</tr>"
			}
			table.html(html)
		},
		fillSeconds : function() {
			var table = this.widget
					.find(".timepicker .timepicker-seconds table");
			table.parent().hide();
			var html = "";
			var current = 0;
			for (var i = 0; i < 5; i++) {
				html += "<tr>";
				for (var j = 0; j < 4; j += 1) {
					var c = current.toString();
					html += '<td class="second">' + padLeft(c, 2, "0")
							+ "</td>";
					current += 3
				}
				html += "</tr>"
			}
			table.html(html)
		},
		fillTime : function() {
			if (!this._date)
				return;
			var timeComponents = this.widget
					.find(".timepicker span[data-time-component]");
			var table = timeComponents.closest("table");
			var is12HourFormat = this.options.pick12HourFormat;
			var hour = this._date.getUTCHours();
			var period = "AM";
			if (is12HourFormat) {
				if (hour >= 12)
					period = "PM";
				if (hour === 0)
					hour = 12;
				else if (hour != 12)
					hour = hour % 12;
				this.widget.find(".timepicker [data-action=togglePeriod]")
						.text(period)
			}
			hour = padLeft(hour.toString(), 2, "0");
			var minute = padLeft(this._date.getUTCMinutes().toString(), 2, "0");
			var second = padLeft(this._date.getUTCSeconds().toString(), 2, "0");
			timeComponents.filter("[data-time-component=hours]").text(hour);
			timeComponents.filter("[data-time-component=minutes]").text(minute);
			timeComponents.filter("[data-time-component=seconds]").text(second)
		},
		click : function(e) {
			e.stopPropagation();
			e.preventDefault();
			this._unset = false;
			var target = $(e.target).closest("span, td, th");
			if (target.length === 1) {
				if (!target.is(".disabled")) {
					switch (target[0].nodeName.toLowerCase()) {
					case "th":
						switch (target[0].className) {
						case "switch":
							this.showMode(1);
							break;
						case "prev":
						case "next":
							var vd = this.viewDate;
							var navFnc = DPGlobal.modes[this.viewMode].navFnc;
							var step = DPGlobal.modes[this.viewMode].navStep;
							if (target[0].className === "prev")
								step = step * -1;
							vd["set" + navFnc](vd["get" + navFnc]() + step);
							this.fillDate();
							this.set();
							break
						}
						break;
					case "span":
						if (target.is(".month")) {
							var month = target.parent().find("span").index(
									target);
							this.viewDate.setUTCMonth(month)
						} else {
							var year = parseInt(target.text(), 10) || 0;
							this.viewDate.setUTCFullYear(year)
						}
						if (this.viewMode !== 0) {
							this._date = UTCDate(
									this.viewDate.getUTCFullYear(),
									this.viewDate.getUTCMonth(), this.viewDate
											.getUTCDate(), this._date
											.getUTCHours(), this._date
											.getUTCMinutes(), this._date
											.getUTCSeconds(), this._date
											.getUTCMilliseconds());
							this.notifyChange()
						}
						this.showMode(-1);
						this.fillDate();
						this.set();
						break;
					case "td":
						if (target.is(".day")) {
							var day = parseInt(target.text(), 10) || 1;
							var month = this.viewDate.getUTCMonth();
							var year = this.viewDate.getUTCFullYear();
							if (target.is(".old")) {
								if (month === 0) {
									month = 11;
									year -= 1
								} else {
									month -= 1
								}
							} else if (target.is(".new")) {
								if (month == 11) {
									month = 0;
									year += 1
								} else {
									month += 1
								}
							}
							this._date = UTCDate(year, month, day, this._date
									.getUTCHours(), this._date.getUTCMinutes(),
									this._date.getUTCSeconds(), this._date
											.getUTCMilliseconds());
							this.viewDate = UTCDate(year, month, Math.min(28,
									day), 0, 0, 0, 0);
							this.fillDate();
							this.set();
							this.notifyChange()
						}
						break
					}
				}
			}
		},
		actions : {
			incrementHours : function(e) {
				this._date.setUTCHours(this._date.getUTCHours() + 1)
			},
			incrementMinutes : function(e) {
				this._date.setUTCMinutes(this._date.getUTCMinutes() + 1)
			},
			incrementSeconds : function(e) {
				this._date.setUTCSeconds(this._date.getUTCSeconds() + 1)
			},
			decrementHours : function(e) {
				this._date.setUTCHours(this._date.getUTCHours() - 1)
			},
			decrementMinutes : function(e) {
				this._date.setUTCMinutes(this._date.getUTCMinutes() - 1)
			},
			decrementSeconds : function(e) {
				this._date.setUTCSeconds(this._date.getUTCSeconds() - 1)
			},
			togglePeriod : function(e) {
				var hour = this._date.getUTCHours();
				if (hour >= 12)
					hour -= 12;
				else
					hour += 12;
				this._date.setUTCHours(hour)
			},
			showPicker : function() {
				this.widget.find(".timepicker > div:not(.timepicker-picker)")
						.hide();
				this.widget.find(".timepicker .timepicker-picker").show()
			},
			showHours : function() {
				this.widget.find(".timepicker .timepicker-picker").hide();
				this.widget.find(".timepicker .timepicker-hours").show()
			},
			showMinutes : function() {
				this.widget.find(".timepicker .timepicker-picker").hide();
				this.widget.find(".timepicker .timepicker-minutes").show()
			},
			showSeconds : function() {
				this.widget.find(".timepicker .timepicker-picker").hide();
				this.widget.find(".timepicker .timepicker-seconds").show()
			},
			selectHour : function(e) {
				var tgt = $(e.target);
				var value = parseInt(tgt.text(), 10);
				if (this.options.pick12HourFormat) {
					var current = this._date.getUTCHours();
					if (current >= 12) {
						if (value != 12)
							value = (value + 12) % 24
					} else {
						if (value === 12)
							value = 0;
						else
							value = value % 12
					}
				}
				this._date.setUTCHours(value);
				this.actions.showPicker.call(this)
			},
			selectMinute : function(e) {
				var tgt = $(e.target);
				var value = parseInt(tgt.text(), 10);
				this._date.setUTCMinutes(value);
				this.actions.showPicker.call(this)
			},
			selectSecond : function(e) {
				var tgt = $(e.target);
				var value = parseInt(tgt.text(), 10);
				this._date.setUTCSeconds(value);
				this.actions.showPicker.call(this)
			}
		},
		doAction : function(e) {
			e.stopPropagation();
			e.preventDefault();
			if (!this._date)
				this._date = UTCDate(1970, 0, 0, 0, 0, 0, 0);
			var action = $(e.currentTarget).data("action");
			var rv = this.actions[action].apply(this, arguments);
			this.set();
			this.fillTime();
			this.notifyChange();
			return rv
		},
		stopEvent : function(e) {
			e.stopPropagation();
			e.preventDefault()
		},
		keydown : function(e) {
			var self = this, k = e.which, input = $(e.target);
			if (k == 8 || k == 46) {
				setTimeout(function() {
					self._resetMaskPos(input)
				})
			}
		},
		keypress : function(e) {
			var k = e.which;
			if (k == 8 || k == 46) {
				return
			}
			var input = $(e.target);
			var c = String.fromCharCode(k);
			var val = input.val() || "";
			val += c;
			var mask = this._mask[this._maskPos];
			if (!mask) {
				return false
			}
			if (mask.end != val.length) {
				return
			}
			if (!mask.pattern.test(val.slice(mask.start))) {
				val = val.slice(0, val.length - 1);
				while ((mask = this._mask[this._maskPos]) && mask.character) {
					val += mask.character;
					this._maskPos++
				}
				val += c;
				if (mask.end != val.length) {
					input.val(val);
					return false
				} else {
					if (!mask.pattern.test(val.slice(mask.start))) {
						input.val(val.slice(0, mask.start));
						return false
					} else {
						input.val(val);
						this._maskPos++;
						return false
					}
				}
			} else {
				this._maskPos++
			}
		},
		change : function(e) {
			if (this.ignoreChangeEvent != true) {
				this.externalChange = true;
				var input = $(e.target); 
				var val = input.val();
				if (this._formatPattern.test(val)) {
					this.update();
					this.setValue(this._date.getTime());
					this.notifyChange();
					this.set()
				} else if (val && val.trim()) {
					this.setValue(this._date.getTime());
					if (this._date)
						this.set();
					else
						input.val("")
				} else {
					if (this._date) {
						this.setValue(null);
						this.notifyChange();
						this._unset = true
					}
				}
				this._resetMaskPos(input)
			}
			this.ignoreChangeEvent = false; 
			this.externalChange = false;
		},
		showMode : function(dir) {
			if (dir) {
				this.viewMode = Math.max(this.minViewMode, Math.min(2,
						this.viewMode + dir))
			}
			this.widget.find(".datepicker > div").hide().filter(
					".datepicker-" + DPGlobal.modes[this.viewMode].clsName)
					.show()
		},
		destroy : function() {
			this._detachDatePickerEvents();
			this._detachDatePickerGlobalEvents();
			this.widget.remove();
			this.$element.removeData("datetimepicker");
			this.component.removeData("datetimepicker")
		},
		formatDate : function(d) {
			return this.format.replace(formatReplacer, function(match) {
				var methodName, property, rv, len = match.length;
				if (match === "ms")
					len = 1;
				property = dateFormatComponents[match].property;
				if (property === "Hours12") {
					rv = d.getUTCHours();
					if (rv === 0)
						rv = 12;
					else if (rv !== 12)
						rv = rv % 12
				} else if (property === "Period12") {
					if (d.getUTCHours() >= 12)
						return "PM";
					else
						return "AM"
				} else {
					methodName = "get" + property;
					rv = d[methodName]()
				}
				if (methodName === "getUTCMonth")
					rv = rv + 1;
				if (methodName === "getUTCYear")
					rv = rv + 1900 - 2e3;
				return padLeft(rv.toString(), len, "0")
			})
		},
		parseDate : function(str) {
			var match, i, property, methodName, value, parsed = {};
			if (!(match = this._formatPattern.exec(str)))
				return null;
			for (i = 1; i < match.length; i++) {
				property = this._propertiesByIndex[i];
				if (!property)
					continue;
				value = match[i];
				if (/^\d+$/.test(value))
					value = parseInt(value, 10);
				parsed[property] = value
			}
			return this._finishParsingDate(parsed)
		},
		_resetMaskPos : function(input) {
			var val = input.val();
			for (var i = 0; i < this._mask.length; i++) {
				if (this._mask[i].end > val.length) {
					this._maskPos = i;
					break
				} else if (this._mask[i].end === val.length) {
					this._maskPos = i + 1;
					break
				}
			}
		},
		_finishParsingDate : function(parsed) {
			var year, month, date, hours, minutes, seconds, milliseconds;
			year = parsed.UTCFullYear;
			if (parsed.UTCYear)
				year = 2e3 + parsed.UTCYear;
			if (!year)
				year = 1970;
			if (parsed.UTCMonth)
				month = parsed.UTCMonth - 1;
			else
				month = 0;
			date = parsed.UTCDate || 1;
			hours = parsed.UTCHours || 0;
			minutes = parsed.UTCMinutes || 0;
			seconds = parsed.UTCSeconds || 0;
			milliseconds = parsed.UTCMilliseconds || 0;
			if (parsed.Hours12) {
				hours = parsed.Hours12
			}
			if (parsed.Period12) {
				if (/pm/i.test(parsed.Period12)) {
					if (hours != 12)
						hours = (hours + 12) % 24
				} else {
					hours = hours % 12
				}
			}
			return UTCDate(year, month, date, hours, minutes, seconds,
					milliseconds)
		},
		_compileFormat : function() {
			var match, component, components = [], mask = [], str = this.format, propertiesByIndex = {}, i = 0, pos = 0;
			while (match = formatComponent.exec(str)) {
				component = match[0];
				if (component in dateFormatComponents) {
					i++;
					propertiesByIndex[i] = dateFormatComponents[component].property;
					components.push("\\s*"
							+ dateFormatComponents[component].getPattern(this)
							+ "\\s*");
					mask.push({
						pattern : new RegExp(dateFormatComponents[component]
								.getPattern(this)),
						property : dateFormatComponents[component].property,
						start : pos,
						end : pos += component.length
					})
				} else {
					components.push(escapeRegExp(component));
					mask.push({
						pattern : new RegExp(escapeRegExp(component)),
						character : component,
						start : pos,
						end : ++pos
					})
				}
				str = str.slice(component.length)
			}
			this._mask = mask;
			this._maskPos = 0;
			this._formatPattern = new RegExp("^\\s*" + components.join("")
					+ "\\s*$");
			this._propertiesByIndex = propertiesByIndex
		},
		_attachDatePickerEvents : function() {
			var self = this;
			this.widget.on("click", ".datepicker *", $.proxy(this.click, this));
			this.widget.on("click", "[data-action]", $.proxy(this.doAction,
					this));
			this.widget.on("mousedown", $.proxy(this.stopEvent, this));
			if (this.pickDate && this.pickTime) {
				this.widget.on("click.togglePicker", ".accordion-toggle",
						function(e) {
							e.stopPropagation();
							var $this = $(this);
							var $parent = $this.closest("ul");
							var expanded = $parent.find(".collapse.in");
							var closed = $parent.find(".collapse:not(.in)");
							if (expanded && expanded.length) {
								var collapseData = expanded.data("collapse");
								if (collapseData && collapseData.transitioning)
									return;
								expanded.collapse("hide");
								closed.collapse("show");
								$this.find("i").toggleClass(
										self.timeIcon + " " + self.dateIcon);
								self.$element.find(".add-on i").toggleClass(
										self.timeIcon + " " + self.dateIcon)
							}
						})
			}
			if (this.isInput) {
				this.$element.on({
					focus : $.proxy(this.show, this),
					change : $.proxy(this.change, this)
				});
				if (this.options.maskInput) {
					this.$element.on({
						keydown : $.proxy(this.keydown, this),
						keypress : $.proxy(this.keypress, this)
					})
				}
			} else {
				this.$element.on({
					change : $.proxy(this.change, this)
				}, "input");
				if (this.options.maskInput) {
					this.$element.on({
						keydown : $.proxy(this.keydown, this),
						keypress : $.proxy(this.keypress, this)
					}, "input")
				}
			}
		},
		_attachDatePickerGlobalEvents : function() {
			$(window).on("resize.datetimepicker" + this.id,
					$.proxy(this.place, this));
		},
		_detachDatePickerEvents : function() {
			this.widget.off("click", ".datepicker *", this.click);
			this.widget.off("click", "[data-action]");
			this.widget.off("mousedown", this.stopEvent);
			if (this.pickDate && this.pickTime) {
				this.widget.off("click.togglePicker")
			}
			if (this.isInput) {
				this.$element.off({
					focus : this.show,
					change : this.change
				});
				if (this.options.maskInput) {
					this.$element.off({
						keydown : this.keydown,
						keypress : this.keypress
					})
				}
			} else {
				this.$element.off({
					change : this.change
				}, "input");
				if (this.options.maskInput) {
					this.$element.off({
						keydown : this.keydown,
						keypress : this.keypress
					}, "input")
				}
				if (this.component) {
					this.component.off("click", this.show)
				} else {
					this.$element.off("click", this.show)
				}
			}
		},
		_detachDatePickerGlobalEvents : function() {
			$(window).off("resize.datetimepicker" + this.id);
			if (!this.isInput) {
				$(document).off("mousedown.datetimepicker" + this.id)
			}
		}
	};
	$.fn.datetimepicker = function(option, val) {
		return this
				.each(function() {
					var $this = $(this), data = $this.data("datetimepicker"), options = typeof option === "object"
							&& option;
					if (!data) {
						$this
								.data(
										"datetimepicker",
										data = new DateTimePicker(
												this,
												$
														.extend(
																{},
																$.fn.datetimepicker.defaults,
																options)))
					}
					if (typeof option === "string")
						data[option](val)
				})
	};
	$.fn.datetimepicker.defaults = {
		maskInput : false,
		pickDate : true,
		pickTime : true,
		pick12HourFormat : false,
		pickSeconds : true,
		startDate : -Infinity,
		endDate : Infinity,
		collapse : true
	};
	$.fn.datetimepicker.Constructor = DateTimePicker;
	var dpgId = 0;
	var dates = $.fn.datetimepicker.dates = {
		en : {
			days : [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
					"Friday", "Saturday", "Sunday" ],
			daysShort : [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
					"Sun" ],
			daysMin : [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su" ],
			months : [ "January", "February", "March", "April", "May", "June",
					"July", "August", "September", "October", "November",
					"December" ],
			monthsShort : [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
					"Aug", "Sep", "Oct", "Nov", "Dec" ]
		}
	};
	var dateFormatComponents = {
		dd : {
			property : "UTCDate",
			getPattern : function() {
				return "(0?[1-9]|[1-2][0-9]|3[0-1])\\b"
			}
		},
		MM : {
			property : "UTCMonth",
			getPattern : function() {
				return "(0?[1-9]|1[0-2])\\b"
			}
		},
		yy : {
			property : "UTCYear",
			getPattern : function() {
				return "(\\d{2})\\b"
			}
		},
		yyyy : {
			property : "UTCFullYear",
			getPattern : function() {
				return "(\\d{4})\\b"
			}
		},
		hh : {
			property : "UTCHours",
			getPattern : function() {
				return "(0?[0-9]|1[0-9]|2[0-3])\\b"
			}
		},
		mm : {
			property : "UTCMinutes",
			getPattern : function() {
				return "(0?[0-9]|[1-5][0-9])\\b"
			}
		},
		ss : {
			property : "UTCSeconds",
			getPattern : function() {
				return "(0?[0-9]|[1-5][0-9])\\b"
			}
		},
		ms : {
			property : "UTCMilliseconds",
			getPattern : function() {
				return "([0-9]{1,3})\\b"
			}
		},
		HH : {
			property : "Hours12",
			getPattern : function() {
				return "(0?[1-9]|1[0-2])\\b"
			}
		},
		PP : {
			property : "Period12",
			getPattern : function() {
				return "(AM|PM|am|pm|Am|aM|Pm|pM)\\b"
			}
		}
	};
	var keys = [];
	for ( var k in dateFormatComponents)
		keys.push(k);
	keys[keys.length - 1] += "\\b";
	keys.push(".");
	var formatComponent = new RegExp(keys.join("\\b|"));
	keys.pop();
	var formatReplacer = new RegExp(keys.join("\\b|"), "g");
	function escapeRegExp(str) {
		return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")
	}
	function padLeft(s, l, c) {
		if (l < s.length)
			return s;
		else
			return Array(l - s.length + 1).join(c || " ") + s
	}
	function getTemplate(newId, timeIcon, pickDate, pickTime, is12Hours, showSeconds,
			collapse) {
		if (pickDate && pickTime) {
			return '<div ' + (newId ? 'id=' + newId : "" )
					+ ' class="bootstrap-datetimepicker-widget dropdown-menu">'
					+ "<ul>"
					+ "<li"
					+ (collapse ? ' class="collapse in"' : "")
					+ ">"
					+ '<div class="datepicker">'
					+ DPGlobal.template
					+ "</div>"
					+ "</li>"
					+ '<li class="picker-switch accordion-toggle"><a><i class="'
					+ timeIcon
					+ '"></i></a></li>'
					+ "<li"
					+ (collapse ? ' class="collapse"' : "")
					+ ">"
					+ '<div class="timepicker">'
					+ TPGlobal.getTemplate(is12Hours, showSeconds)
					+ "</div>"
					+ "</li>" + "</ul>" + "</div>"
		} else if (pickTime) {
			return '<div ' + (newId ? 'id=' + newId : "" )
					+ ' class="bootstrap-datetimepicker-widget dropdown-menu">'
					+ '<div class="timepicker">'
					+ TPGlobal.getTemplate(is12Hours, showSeconds)
					+ "</div>"
					+ "</div>"
		} else {
			return '<div ' + (newId ? 'id=' + newId : "" )
					+ ' class="bootstrap-datetimepicker-widget dropdown-menu">'
					+ '<div class="datepicker">'
					+ DPGlobal.template
					+ "</div>"
					+ "</div>"
		}
	}
	function UTCDate() {
		return new Date(Date.UTC.apply(Date, arguments))
	}
	var DPGlobal = {
		modes : [ {
			clsName : "days",
			navFnc : "UTCMonth",
			navStep : 1
		}, {
			clsName : "months",
			navFnc : "UTCFullYear",
			navStep : 1
		}, {
			clsName : "years",
			navFnc : "UTCFullYear",
			navStep : 10
		} ],
		isLeapYear : function(year) {
			return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0
		},
		getDaysInMonth : function(year, month) {
			return [ 31, DPGlobal.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30,
					31, 31, 30, 31, 30, 31 ][month]
		},
		headTemplate : "<thead>" + "<tr>" + '<th class="prev">&lsaquo;</th>'
				+ '<th colspan="5" class="switch"></th>'
				+ '<th class="next">&rsaquo;</th>' + "</tr>" + "</thead>",
		contTemplate : '<tbody><tr><td colspan="7"></td></tr></tbody>'
	};
	DPGlobal.template = '<div class="datepicker-days">'
			+ '<table class="table-condensed">' + DPGlobal.headTemplate
			+ "<tbody></tbody>" + "</table>" + "</div>"
			+ '<div class="datepicker-months">'
			+ '<table class="table-condensed">' + DPGlobal.headTemplate
			+ DPGlobal.contTemplate + "</table>" + "</div>"
			+ '<div class="datepicker-years">'
			+ '<table class="table-condensed">' + DPGlobal.headTemplate
			+ DPGlobal.contTemplate + "</table>" + "</div>";
	var TPGlobal = {
		hourTemplate : '<span data-action="showHours" data-time-component="hours" class="timepicker-hour"></span>',
		minuteTemplate : '<span data-action="showMinutes" data-time-component="minutes" class="timepicker-minute"></span>',
		secondTemplate : '<span data-action="showSeconds" data-time-component="seconds" class="timepicker-second"></span>'
	};
	TPGlobal.getTemplate = function(is12Hours, showSeconds) {
		return '<div class="timepicker-picker">'
				+ '<table class="table-condensed"'
				+ (is12Hours ? ' data-hour-format="12"' : "")
				+ ">"
				+ "<tr>"
				+ '<td><a href="#" class="btn" data-action="incrementHours"><i class="icon-chevron-up"></i></a></td>'
				+ '<td class="separator"></td>'
				+ '<td><a href="#" class="btn" data-action="incrementMinutes"><i class="icon-chevron-up"></i></a></td>'
				+ (showSeconds ? '<td class="separator"></td>'
						+ '<td><a href="#" class="btn" data-action="incrementSeconds"><i class="icon-chevron-up"></i></a></td>'
						: "")
				+ (is12Hours ? '<td class="separator"></td>' : "")
				+ "</tr>"
				+ "<tr>"
				+ "<td>"
				+ TPGlobal.hourTemplate
				+ "</td> "
				+ '<td class="separator">:</td>'
				+ "<td>"
				+ TPGlobal.minuteTemplate
				+ "</td> "
				+ (showSeconds ? '<td class="separator">:</td>' + "<td>"
						+ TPGlobal.secondTemplate + "</td>" : "")
				+ (is12Hours ? '<td class="separator"></td>'
						+ "<td>"
						+ '<button type="button" class="btn btn-primary" data-action="togglePeriod"></button>'
						+ "</td>"
						: "")
				+ "</tr>"
				+ "<tr>"
				+ '<td><a href="#" class="btn" data-action="decrementHours"><i class="icon-chevron-down"></i></a></td>'
				+ '<td class="separator"></td>'
				+ '<td><a href="#" class="btn" data-action="decrementMinutes"><i class="icon-chevron-down"></i></a></td>'
				+ (showSeconds ? '<td class="separator"></td>'
						+ '<td><a href="#" class="btn" data-action="decrementSeconds"><i class="icon-chevron-down"></i></a></td>'
						: "")
				+ (is12Hours ? '<td class="separator"></td>' : "")
				+ "</tr>"
				+ "</table>"
				+ "</div>"
				+ '<div class="timepicker-hours" data-action="selectHour">'
				+ '<table class="table-condensed">'
				+ "</table>"
				+ "</div>"
				+ '<div class="timepicker-minutes" data-action="selectMinute">'
				+ '<table class="table-condensed">'
				+ "</table>"
				+ "</div>"
				+ (showSeconds ? '<div class="timepicker-seconds" data-action="selectSecond">'
						+ '<table class="table-condensed">'
						+ "</table>"
						+ "</div>"
						: "")
	}
})(window.jQuery);